package AwesomeVersion;

import java.awt.*;
import java.awt.event.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;

import javax.swing.*;
import javax.swing.text.DefaultCaret;

/**
 * Graphical user interface to a Tic Tac Toe application. The GUI is incomplete
 * because it has no associated player. It also needs a routine for checking if
 * one of the players have got five marks in a row.
 */
public class TicTacToeGui extends JFrame implements Constants, ActionListener {
	/** Textfield showing what mark you use ('X' or 'O') */
	private JTextField id;
	/** TextArea giving feedback to the user */
	private TextArea display;
	/** Used for auto-scroll */
	private DefaultCaret caret;
	/** The panel containing the board */
	private JPanel boardPanel;
	/** The squares of the board */
	private Square board[][];
	/** The menu bar */
	private JMenuBar menuBar;
	/** The game submenu */
	private JMenu gameMenu;
	/** Game submenu choices */
	private JMenuItem newGameItem, quitItem;

	/** The name of the player using this GUI */
	private String myName;
	/** The mark used by this player ('X' or 'O') */
	private char myMark;

	private String myIp;
	private int myPort = 1337;
	private String remoteIp;
	private int remotePort;
	private boolean myTurn;

	private SocketAction theGame; // The Game Connection

	/**
	 * Creates a new GUI.
	 * 
	 * @param name
	 *            The name of that player.
	 * @param mark
	 *            The mark used by that player.
	 * @throws Exception
	 * @throws RemoteException
	 */
	public TicTacToeGui(String name, String remIP, int remPort)
			throws RemoteException, Exception {
		myName = name;
		myMark = initGameConnection(remIP, remPort); // Creates a connection
		myIp = theGame.getMyIP();
		myPort = theGame.getMyPort();
		myTurn = theGame.getMyTurn();
		remoteIp = theGame.getRemoteIP();
		remotePort = theGame.getRemotePort();

		// Create GUI components:
		// The display at the bottom:
		display = new TextArea("", 4, 30, TextArea.SCROLLBARS_VERTICAL_ONLY);
		DefaultCaret caret = new DefaultCaret();
		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
		display.setEditable(false);
		// The name field at the top:
		id = new JTextField();
		id.setEditable(false);
		setIdText();
		// The board:
		JPanel gridPanel = new JPanel();
		gridPanel.setLayout(new GridLayout(BOARD_SIZE, BOARD_SIZE, 0, 0));
		board = new Square[BOARD_SIZE][BOARD_SIZE];
		for (int row = 0; row < board.length; row++)
			for (int col = 0; col < board[row].length; col++) {
				board[row][col] = new Square(this, row, col);
				gridPanel.add(board[row][col]);
			}
		boardPanel = new JPanel();
		boardPanel.add(gridPanel);

		// Place the components:
		Container cp = getContentPane();
		cp.setLayout(new BorderLayout());
		cp.add("South", display);
		cp.add("North", id);
		cp.add("Center", boardPanel);

		// Create the menu.
		menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		gameMenu = new JMenu("Game");
		gameMenu.setMnemonic(KeyEvent.VK_G);
		menuBar.add(gameMenu);
		newGameItem = new JMenuItem("New game", KeyEvent.VK_N);
		newGameItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
		gameMenu.add(newGameItem);
		quitItem = new JMenuItem("Quit", KeyEvent.VK_Q);
		quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4,
				ActionEvent.ALT_MASK));
		gameMenu.add(quitItem);

		// Add listeners
		newGameItem.addActionListener(this);
		quitItem.addActionListener(this);
		// Add an anonymous WindowListener which calls quit() when the window is
		// closing
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				quit();
			}
		});

		// Add initial information to bottom display after established
		// connection
		if (theGame.getMyConnectionStatus()) {
			display.append("Connected to: " + remoteIp + " at port: "
					+ remotePort + "\n");

		} else {
			display.append("Server not found..." + "\n");
			display.append("Starting new server @ " + myIp + ":" + myPort
					+ "\n");
			display.append("Listening..." + "\n");
		}

		// Place and show the window:
		setTitle("Tic Tac Toe: " + name);
		setSize(WIN_WIDTH, WIN_HEIGHT);
		setLocation(200, 200);
		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		setVisible(true);
	}

	/**
	 * Called by the Square class when an empty square is clicked.
	 * 
	 * @param row
	 *            The row of the square that was clicked.
	 * @param column
	 *            The column of the square that was clicked.
	 * @throws RemoteException
	 */
	public void squareClicked(int row, int column) {
		if (theGame.getMyConnectionStatus()) {
			if (theGame.getMyTurn()) {
				setMark(row, column, myMark);
				if (theGame.getIAmServer()) { // If you are server
					theGame.setMyCurrentMove(1, row, column);
					try {
						theGame.sendToClient();
					} catch (RemoteException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					theGame.setMyCurrentMove(1, row, column);
					theGame.setMyTurn(false);

					try {
						theGame.getRmiServer().sendToServer(
								theGame.getMyCurrentMove());

					} catch (RemoteException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			} else {
				JOptionPane.showMessageDialog(null, "It is not your turn!",
						"Wait for your turn!", 0);
			}

		} else {
			JOptionPane
					.showMessageDialog(
							null,
							"You are not connected with a remote player!\n Are you #RONERY?",
							"Not connected! #RONERY?", 0);
		}
	}

	/**
	 * Marks the specified square of the board with the specified mark.
	 * 
	 * @param row
	 *            The row of the square to mark.
	 * @param column
	 *            The column of the square to mark.
	 * @param mark
	 *            The mark to use.
	 */
	public void setMark(int row, int column, char mark) {
		board[row][column].setMark(mark);
		repaint();
	}

	/**
	 * Called when a menu item has been selected.
	 * 
	 * @param e
	 *            The ActionEvent that occured.
	 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == newGameItem)
			newGame();
		else if (e.getSource() == quitItem)
			quit();
	}

	/**
	 * Starts a new game, if the user confirms it in a dialog box.
	 */
	public void newGame() {
		// This method must be modified!
		if (JOptionPane.showConfirmDialog(this,
				"Are you sure you want to start a new game?", "Start over?",
				JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
			clearBoard();
		}
	}

	/**
	 * Removes all marks from the board.
	 */
	public void clearBoard() {
		for (int row = 0; row < board.length; row++)
			for (int col = 0; col < board[row].length; col++)
				board[row][col].setMark(' ');
		repaint();
	}

	/**
	 * Exits the game, if the user confirms it in a dialog box. Should notify
	 * the opponent that we left the game.
	 */
	public void quit() {
		// This method should be modified!
		if (JOptionPane.showConfirmDialog(this,
				"Are you sure you want to quit?", "Really quit?",
				JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
			System.exit(0);
		}
	}

	/**
	 * Outputs a message to the user.
	 * 
	 * @param s
	 *            The string to display. Adds a newline to the end of the
	 *            string.
	 */
	public void println(String s) {
		display.append(s + "\n");
	}

	/**
	 * Outputs a message to the user.
	 * 
	 * @param s
	 *            The string to display.
	 */
	public void print(String s) {
		display.append(s);
	}

	public void setIdText() {
		id.setText(myName + ": You are player " + myMark);
	}

	public String getMyName() {
		return myName;
	}

	/**
	 * @param remIP
	 *            The remote IP
	 * @param remPort
	 *            The remote port
	 * @return Returns the assigned player mark Initializes a new game
	 *         connection, either as server or client based on the result of a
	 *         connection attempt to given server IP and port taken from
	 *         parameters
	 * 
	 */
	public char initGameConnection(String remIP, int remPort)
			throws RemoteException, Exception {
		theGame = new SocketAction(remIP, remPort, this);
		return theGame.getMyMark();
	}

	/**
	 * Starts up a GUI without an associated player, in order to check the
	 * appearance of the GUI.
	 * 
	 * @throws Exception
	 * @throws RemoteException
	 */
	public static void main(String args[]) throws RemoteException, Exception {
		System.setSecurityManager(new LiberalSecurityManager());
		String tempPlayerName = ((String) (JOptionPane.showInputDialog(null,
				"What is your name?", "Enter your name",
				JOptionPane.QUESTION_MESSAGE, null, null, "Arne")));
		String remIP = ((String) (JOptionPane.showInputDialog(null,
				"What is the remote IP?", "Enter remote IP",
				JOptionPane.QUESTION_MESSAGE, null, null, "127.0.0.1")));
		int remPort = (Integer.parseInt((String) (JOptionPane.showInputDialog(
				null, "What is the remote port?", "Enter remote port",
				JOptionPane.QUESTION_MESSAGE, null, null, "1337"))));

		TicTacToeGui playerGui = new TicTacToeGui(tempPlayerName, remIP,
				remPort);
	}
}
